package controllers;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import models.CommercialOfferer;
import models.Event;
import models.EventCategory;
import models.Offer;
import models.PrivateOfferer;
import play.mvc.*;

public class Search extends Controller {
	
	/**
	 * 
	 * @param category
	 *            The category of the event
	 * @param initialLetter
	 *            First letter of the event to be found
	 * @return List of Events of particular category in chronological order
	 */
	public static List<Event> searchForUpcomingEvents(EventCategory category,
			String initialLetter) {
		List<Event> eventList;
		
		//Different queries depending on whether a category or an initial letter is given
		if ((category != null && initialLetter != null)){
			eventList = Event
					.find(Queries.FIND_EVENT_BY_INITIALLETTER_DATE_CATEGORY_ORDER_BY_NAME,
							initialLetter + "%", new Date(), category).fetch();
    	} else if(initialLetter != null){
    		eventList = Event
    				.find(Queries.FIND_EVENT_BY_INITIALLETTER_DATE_ORDER_BY_NAME,
    				initialLetter + "%", new Date()).fetch();
    	} else if(category != null){
    		eventList = Event
    				.find(Queries.FIND_EVENT_BY_DATE_CATEGORY_ORDER_BY_NAME,
    				new Date(), category).fetch();
    	} else {
    		eventList = Event.find(Queries.FIND_EVENT_BY_DATE_ORDER_BY_NAME, new Date()).fetch();
    	}
		
		return eventList;
	}
	
	public static List<String> dropdownEventList() {
		List<String> dropdownEventList;
		dropdownEventList = Event.find(Queries.FIND_EVENT_BY_DATE_ORDER_BY_NAME_GROUP_BY_NAME, new Date()).fetch();
		
		return dropdownEventList;
	}
	
	public static List<Event> searchEventByName(String name) {
		List<Event> eventList;
		eventList = Event.find(Queries.FIND_EVENT_BY_NAME_AND_DATE_ORDER_BY_NAME, name, new Date()).fetch();
		return eventList;
	}
	
	public static List<Event> searchUpcomingInactiveEvents() {
		return Event.find(Queries.FIND_EVENT_BY_DATE_AND_NOT_ACTIVE_ORDER_BY_NAME, new Date()).fetch();
	}
	
	/**
	 * Some wrapper methods
	 */
	
	public static List<Event> searchForUpcomingEvents() {
		return searchForUpcomingEvents(null, null);
	}
	
	public static List<Event> searchForUpcomingEvents(EventCategory category) {
		return searchForUpcomingEvents(category, null);
	}
	
	public static List<Event> searchForUpcomingEvents(String initialLetter) {
		return searchForUpcomingEvents(null, initialLetter);
	}
	
	public static List<Event> searchForUpcomingEvents(int amount) {
		return searchForUpcomingEvents(null, null, amount);
	}
	
	/**
	 * 
	 * @param category
	 *            The category of the event
	 * @param initialLetter
	 *            First letter of the event to be found
	 * @param amount
	 * 			  How many events should be looked for
	 * @return List of Events of particular category in chronological order
	 */
	public static List<Event> searchForUpcomingEvents(EventCategory category,
			String initialLetter, int amount) {
		List<Event> eventList;
		
		//Different queries depending on whether a category or an initial letter is given
		if ((category != null && initialLetter != null)){
			eventList = Event
					.find(Queries.FIND_EVENT_BY_INITIALLETTER_DATE_CATEGORY_ORDER_BY_NAME,
							initialLetter + "%", new Date(), category).fetch(amount);
    	} else if(initialLetter != null){
    		eventList = Event
    				.find(Queries.FIND_EVENT_BY_INITIALLETTER_DATE_ORDER_BY_NAME,
    				initialLetter + "%", new Date()).fetch(amount);
    	} else if(category != null){
    		eventList = Event
    				.find(Queries.FIND_EVENT_BY_DATE_CATEGORY_ORDER_BY_NAME,
    				new Date(), category).fetch(amount);
    	} else {
    		eventList = Event.find(Queries.FIND_EVENT_BY_DATE_ORDER_BY_NAME, new Date()).fetch(amount);
    	}
		
		return eventList;
	}

	/**
	 * 
	 * @param name
	 *            Name of the Event
	 * @param startDate
	 *            Start date of the event
	 * @param endDate
	 *            End date of the event
	 * @param city
	 *            The city where the event takes place
	 * @param category
	 *            The category of the event
	 * @return List of Events that match the specified criteria
	 */
	
	public static List<Event> searchForUpcomingEvents(String name,
			Date startDate, String city, EventCategory category) {
		List<Event> eventList = Event
				.find("name = ? and startDate > ? and startDate = ?  and city = ? and category = ? order by startDate asc",
						name, new Date(), startDate, city, category).fetch();
		return eventList;
	}

	public static List<Event> searchForPopularEvents(EventCategory category,
			String initialLetter, int amount) {
		List<Event> eventList;
		
		//Different queries depending on whether a category or an initial letter is given
		if ((category != null && initialLetter != null)){
			eventList = Event
					.find(Queries.FIND_EVENT_BY_INITIALLETTER_DATE_CATEGORY_ORDER_BY_POPULARITY,
							initialLetter + "%", new Date(), category).fetch(amount);
    	} else if(initialLetter != null){
    		eventList = Event
    				.find(Queries.FIND_EVENT_BY_INITIALLETTER_DATE_ORDER_BY_POPULARITY,
    				initialLetter + "%", new Date()).fetch(amount);
    	} else if(category != null){
    		eventList = Event
    				.find(Queries.FIND_EVENT_BY_DATE_CATEGORY_ORDER_BY_POPULARITY,
    				new Date(), category).fetch(amount);
    	} else {
    		eventList = Event.find(Queries.FIND_EVENT_BY_DATE_ORDER_BY_POPULARITY, new Date()).fetch(amount);
    	}
		
		return eventList;
	}
	
	/**
	 * 
	 * @param id
	 *            The event for which the offers shall be found
	 * @return List of matching offers
	 */
	public static List<Offer> searchForOffers(Long id) {
		Event event = Event.findById(id);
		Collections.sort(event.offers);
		return event.offers;
	}

	/**
	 * TODO: queries in constants!
	 * 
	 * @param event
	 *            The event for which offers are searched
	 * @param fromPrice
	 *            Lower boundary of the price range
	 * @param toPrice
	 *            Upper boundary of the price range
	 * @param includePivateOffers
	 *            true if private offers shall be included, else false
	 * @return
	 */
	public static List<Offer> searchForOffers(Long id, float fromPrice,
			float toPrice, boolean includePrivateOffers, boolean premium) {
		Event event = Event.findById(id);
		List<Offer> offerList;

		if (toPrice < 1) {
			if (includePrivateOffers) {
				offerList = Offer
						.find("event = ? and premium = ? order by startDate asc",
								event, premium).fetch();
			} else {
				offerList = Offer
						.find("event = ? and user.class = CommercialOfferer and premium = ? order by startDate asc",
								event, premium).fetch();
			}
		}
		else {
			if (includePrivateOffers) {
				offerList = Offer
						.find("event = ? and price between ? and ? and premium = ? order by startDate asc",
								event, fromPrice, toPrice, premium).fetch();
			} else {
				offerList = Offer
						.find("event = ? and user.class = CommercialOfferer and price between ? and ? and premium = ? order by startDate asc",
								event, fromPrice, toPrice, premium).fetch();
			}
		}
		return offerList;
	}

}
